# -*- coding: utf-8 -*-
"""
文本编码转换器
支持 UTF-8、GBK 等编码格式的互转
"""

import os
import chardet
from pathlib import Path


class EncodingConverter:
    """文本编码转换器类"""

    def __init__(self):
        pass

    def convert(self, input_path, output_dir, conversion_type):
        """
        转换文本编码
        :param input_path: 输入文件路径
        :param output_dir: 输出目录
        :param conversion_type: 转换类型
        :return: 输出文件路径
        """
        if conversion_type == 'gbk_to_utf8':
            return self.gbk_to_utf8(input_path, output_dir)
        elif conversion_type == 'utf8_to_gbk':
            return self.utf8_to_gbk(input_path, output_dir)
        elif conversion_type == 'auto_to_utf8':
            return self.auto_to_utf8(input_path, output_dir)
        elif conversion_type == 'auto_to_gbk':
            return self.auto_to_gbk(input_path, output_dir)
        else:
            raise ValueError(f"不支持的转换类型: {conversion_type}")

    def gbk_to_utf8(self, input_path, output_dir):
        """
        GBK转UTF-8
        :param input_path: 输入文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(input_path):
            raise FileNotFoundError(f"文件不存在: {input_path}")

        base_name = os.path.basename(input_path)
        name, ext = os.path.splitext(base_name)
        output_path = os.path.join(output_dir, f"{name}_utf8{ext}")

        print(f"\n开始转换: {base_name}")
        print("=" * 60)
        print("转换: GBK → UTF-8")

        try:
            # 读取GBK编码的文件
            with open(input_path, 'r', encoding='gbk') as f:
                content = f.read()

            # 写入UTF-8编码
            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(content)

            # 验证转换
            if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
                print("✓ GBK转UTF-8成功")
                print(f"  输出文件: {os.path.basename(output_path)}")
                return output_path
            else:
                raise Exception("输出文件未生成或为空")

        except UnicodeDecodeError as e:
            print(f"✗ GBK解码失败: 文件可能不是GBK编码")
            print(f"  错误信息: {str(e)}")

            # 尝试自动检测编码
            print("\n尝试自动检测编码...")
            return self.auto_to_utf8(input_path, output_dir)

        except Exception as e:
            print(f"✗ 转换失败: {str(e)}")
            raise Exception(f"GBK转UTF-8失败: {str(e)}")

    def utf8_to_gbk(self, input_path, output_dir):
        """
        UTF-8转GBK
        :param input_path: 输入文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(input_path):
            raise FileNotFoundError(f"文件不存在: {input_path}")

        base_name = os.path.basename(input_path)
        name, ext = os.path.splitext(base_name)
        output_path = os.path.join(output_dir, f"{name}_gbk{ext}")

        print(f"\n开始转换: {base_name}")
        print("=" * 60)
        print("转换: UTF-8 → GBK")

        try:
            # 读取UTF-8编码的文件
            with open(input_path, 'r', encoding='utf-8') as f:
                content = f.read()

            # 写入GBK编码
            with open(output_path, 'w', encoding='gbk') as f:
                f.write(content)

            # 验证转换
            if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
                print("✓ UTF-8转GBK成功")
                print(f"  输出文件: {os.path.basename(output_path)}")
                return output_path
            else:
                raise Exception("输出文件未生成或为空")

        except UnicodeDecodeError as e:
            print(f"✗ UTF-8解码失败: 文件可能不是UTF-8编码")
            print(f"  错误信息: {str(e)}")

            # 尝试自动检测编码
            print("\n尝试自动检测编码...")
            return self.auto_to_gbk(input_path, output_dir)

        except UnicodeEncodeError as e:
            print(f"✗ GBK编码失败: 文件包含GBK不支持的字符")
            print(f"  错误信息: {str(e)}")
            print("\n建议: GBK编码不支持某些Unicode字符，建议使用UTF-8")
            raise Exception(f"UTF-8转GBK失败: 文件包含GBK不支持的字符")

        except Exception as e:
            print(f"✗ 转换失败: {str(e)}")
            raise Exception(f"UTF-8转GBK失败: {str(e)}")

    def auto_to_utf8(self, input_path, output_dir):
        """
        自动检测编码并转换为UTF-8
        :param input_path: 输入文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(input_path):
            raise FileNotFoundError(f"文件不存在: {input_path}")

        base_name = os.path.basename(input_path)
        name, ext = os.path.splitext(base_name)
        output_path = os.path.join(output_dir, f"{name}_utf8{ext}")

        print(f"\n开始转换: {base_name}")
        print("=" * 60)
        print("模式: 自动检测编码 → UTF-8")

        try:
            # 读取文件二进制内容
            with open(input_path, 'rb') as f:
                raw_data = f.read()

            # 自动检测编码
            detected = chardet.detect(raw_data)
            source_encoding = detected['encoding']
            confidence = detected['confidence']

            print(f"检测到编码: {source_encoding} (置信度: {confidence:.2%})")

            # 如果检测不到编码，尝试常见编码
            if not source_encoding or confidence < 0.7:
                print("置信度较低，尝试常见编码...")
                encodings_to_try = ['utf-8', 'gbk', 'gb2312', 'gb18030', 'big5', 'latin1']
            else:
                encodings_to_try = [source_encoding, 'utf-8', 'gbk', 'gb2312', 'latin1']

            # 尝试解码
            content = None
            used_encoding = None

            for encoding in encodings_to_try:
                try:
                    content = raw_data.decode(encoding)
                    used_encoding = encoding
                    print(f"✓ 使用 {encoding} 解码成功")
                    break
                except (UnicodeDecodeError, LookupError):
                    continue

            if content is None:
                raise Exception("无法解码文件，尝试了所有常见编码都失败")

            # 如果已经是UTF-8，直接复制
            if used_encoding.lower().replace('-', '') == 'utf8':
                print("  文件已经是UTF-8编码")
                with open(output_path, 'w', encoding='utf-8') as f:
                    f.write(content)
            else:
                # 转换为UTF-8
                with open(output_path, 'w', encoding='utf-8') as f:
                    f.write(content)
                print(f"  {used_encoding} → UTF-8 转换成功")

            if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
                print("✓ 编码转换成功")
                print(f"  输出文件: {os.path.basename(output_path)}")
                return output_path
            else:
                raise Exception("输出文件未生成或为空")

        except ImportError:
            print("✗ chardet库未安装")
            print("\n建议: pip install chardet")
            raise Exception("自动检测编码失败：需要安装chardet库")

        except Exception as e:
            print(f"✗ 转换失败: {str(e)}")
            raise Exception(f"编码转换失败: {str(e)}")

    def auto_to_gbk(self, input_path, output_dir):
        """
        自动检测编码并转换为GBK
        :param input_path: 输入文件路径
        :param output_dir: 输出目录
        :return: 输出文件路径
        """
        if not os.path.exists(input_path):
            raise FileNotFoundError(f"文件不存在: {input_path}")

        base_name = os.path.basename(input_path)
        name, ext = os.path.splitext(base_name)
        output_path = os.path.join(output_dir, f"{name}_gbk{ext}")

        print(f"\n开始转换: {base_name}")
        print("=" * 60)
        print("模式: 自动检测编码 → GBK")

        try:
            # 读取文件二进制内容
            with open(input_path, 'rb') as f:
                raw_data = f.read()

            # 自动检测编码
            detected = chardet.detect(raw_data)
            source_encoding = detected['encoding']
            confidence = detected['confidence']

            print(f"检测到编码: {source_encoding} (置信度: {confidence:.2%})")

            # 如果检测不到编码，尝试常见编码
            if not source_encoding or confidence < 0.7:
                print("置信度较低，尝试常见编码...")
                encodings_to_try = ['utf-8', 'gbk', 'gb2312', 'gb18030', 'big5', 'latin1']
            else:
                encodings_to_try = [source_encoding, 'utf-8', 'gbk', 'gb2312', 'latin1']

            # 尝试解码
            content = None
            used_encoding = None

            for encoding in encodings_to_try:
                try:
                    content = raw_data.decode(encoding)
                    used_encoding = encoding
                    print(f"✓ 使用 {encoding} 解码成功")
                    break
                except (UnicodeDecodeError, LookupError):
                    continue

            if content is None:
                raise Exception("无法解码文件，尝试了所有常见编码都失败")

            # 如果已经是GBK，直接复制
            if used_encoding.lower() in ['gbk', 'gb2312', 'gb18030']:
                print("  文件已经是GBK系列编码")
                with open(output_path, 'wb') as f:
                    f.write(raw_data)
            else:
                # 转换为GBK
                try:
                    with open(output_path, 'w', encoding='gbk') as f:
                        f.write(content)
                    print(f"  {used_encoding} → GBK 转换成功")
                except UnicodeEncodeError as e:
                    print(f"✗ GBK编码失败: 文件包含GBK不支持的字符")
                    print("\n建议: GBK编码不支持某些Unicode字符")
                    print("      1. 使用UTF-8编码（推荐）")
                    print("      2. 或删除/替换不支持的字符")
                    raise Exception("转换失败: 文件包含GBK不支持的字符")

            if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
                print("✓ 编码转换成功")
                print(f"  输出文件: {os.path.basename(output_path)}")
                return output_path
            else:
                raise Exception("输出文件未生成或为空")

        except ImportError:
            print("✗ chardet库未安装")
            print("\n建议: pip install chardet")
            raise Exception("自动检测编码失败：需要安装chardet库")

        except Exception as e:
            print(f"✗ 转换失败: {str(e)}")
            raise Exception(f"编码转换失败: {str(e)}")

    def detect_encoding(self, file_path):
        """
        检测文件编码
        :param file_path: 文件路径
        :return: (编码名称, 置信度)
        """
        try:
            with open(file_path, 'rb') as f:
                raw_data = f.read()

            detected = chardet.detect(raw_data)
            return detected['encoding'], detected['confidence']

        except Exception as e:
            return None, 0.0
